package edu.bu.cs673.superkids123.parents.view;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.LayoutStyle;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;

import edu.bu.cs673.superkids123.AbstractFrame;
import edu.bu.cs673.superkids123.AbstractNavigationView;
import edu.bu.cs673.superkids123.common.model.Achievement;
import edu.bu.cs673.superkids123.common.model.AchievementRule;
import edu.bu.cs673.superkids123.common.model.AchievementRule.Metric;
import edu.bu.cs673.superkids123.parents.controller.AchievementDetailsController;
import edu.bu.cs673.superkids123.parents.view.dialog.AchievementRuleDialog;

public class AchievementDetailsView extends AbstractNavigationView implements ListSelectionListener, ActionListener {

	private JPanel panel;
	private JLabel nameLabel;
	private JTextField nameField;
	private JLabel descriptionLabel;
	private JTextField descriptionField;
	private JLabel prizeLabel;
	private JTextField prizeField;
	private JLabel pointsLabel;
	private JTextField pointsField;
	private JTable rulesTable;
	private JButton addButton;
	private JButton editButton;
	private JButton deleteButton;
	private JButton saveButton;
	
	public AchievementDetailsView(AbstractFrame mainFrame) {
		super(mainFrame);
	}

	@Override
	public String getTitle() {
		return "Achievement Add/Edit";
	}

	@Override
	public String getBorderTitle() {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * @wbp.parser.entryPoint
	 */
	@Override
	protected JPanel layout() {
		
		nameLabel = new JLabel("Name:");
		nameField = new JTextField();
		
		descriptionLabel = new JLabel("Description:");
		descriptionField = new JTextField();
		
		prizeLabel = new JLabel("Prize:");
		prizeField = new JTextField();
		
		pointsLabel = new JLabel("Points:");
		pointsField = new JTextField();
		
		rulesTable = new JTable(new RulesTableModel());
		rulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		rulesTable.setFillsViewportHeight(true);
		rulesTable.getTableHeader().setResizingAllowed(false);
		rulesTable.getTableHeader().setReorderingAllowed(false);
		rulesTable.getSelectionModel().addListSelectionListener(this);
		JScrollPane achievementPane = new JScrollPane(rulesTable);
		achievementPane.setBorder(BorderFactory.createTitledBorder(" Rules "));
		
		// Buttons
		addButton = new JButton("Add");
		addButton.addActionListener(this);
		
		editButton = new JButton("Edit");
		editButton.setEnabled(false);
		editButton.addActionListener(this);
		
		deleteButton = new JButton("Delete");
		deleteButton.setEnabled(false);
		deleteButton.addActionListener(this);
		
		saveButton = new JButton("Save");
		saveButton.addActionListener(this);
		
		panel = new JPanel();
		GroupLayout layout = new GroupLayout(panel);
		panel.setLayout(layout);
		layout.setAutoCreateGaps(true);
		layout.setAutoCreateContainerGaps(true);
		
		layout.setHorizontalGroup(layout.createSequentialGroup()
			.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
				.addGroup(layout.createSequentialGroup()
					.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
						.addComponent(nameLabel)
						.addComponent(descriptionLabel)
						.addComponent(prizeLabel)
						.addComponent(pointsLabel))
					.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
						.addComponent(nameField)
						.addComponent(descriptionField)
						.addComponent(prizeField)
						.addComponent(pointsField)))
				.addComponent(achievementPane)
				.addGroup(layout.createSequentialGroup()
					.addComponent(addButton)
					.addComponent(editButton)
					.addComponent(deleteButton)
					.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
					.addComponent(saveButton)))
		);
		
		layout.setVerticalGroup(layout.createSequentialGroup()
			.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
				.addComponent(nameLabel)
				.addComponent(nameField))
			.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
				.addComponent(descriptionLabel)
				.addComponent(descriptionField))
			.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
				.addComponent(prizeLabel)
				.addComponent(prizeField))		
			.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
				.addComponent(pointsLabel)
				.addComponent(pointsField))
			.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
				.addComponent(achievementPane))
			.addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
				.addComponent(addButton)
				.addComponent(editButton)
				.addComponent(deleteButton)
				.addComponent(saveButton))
		);
		
		if (AchievementDetailsController.getSelectedAchievement() != null) {
			loadAchievement();
		}
		
		return panel;
	}
	
	/**
	 * Loads the achievement in to this form for editing.
	 * @param achievement
	 */
	public void loadAchievement() {
		Achievement achievement = AchievementDetailsController.getSelectedAchievement();
		
		nameField.setText(achievement.getName());
		descriptionField.setText(achievement.getDescription());
		prizeField.setText(achievement.getPrize());
		pointsField.setText(String.format("%s", achievement.getPoints()));
		
		((RulesTableModel)rulesTable.getModel()).setRules(achievement.getRules());
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		
		if (e.getSource() == addButton) {
			AchievementRule rule = getMainFrame()
					.getController(AchievementDetailsController.class)
					.addRule();
			
			if (rule != null) {
				((RulesTableModel) rulesTable.getModel()).addRule(rule);
				((RulesTableModel) rulesTable.getModel()).fireTableDataChanged();
			}
			
		} else if (e.getSource() == editButton) {
			int selectedIndex = rulesTable.getSelectedRow();

			if (selectedIndex >= 0) {
				AchievementRule rule = ((RulesTableModel) rulesTable.getModel())
						.getRule(selectedIndex);
				
				if (rule == null)
					return;
				
				AchievementRule result = getMainFrame()
						.getController(AchievementDetailsController.class)
						.editRule(rule);
				
				if (result != null) {
					((RulesTableModel) rulesTable.getModel()).editRule(selectedIndex, result);
					((RulesTableModel) rulesTable.getModel()).fireTableDataChanged();
				}
			}
		} else if (e.getSource() == deleteButton) {
			int selectedIndex = rulesTable.getSelectedRow();

			if (selectedIndex >= 0) {
				((RulesTableModel) rulesTable.getModel())
					.deleteRule(selectedIndex);
				((RulesTableModel) rulesTable.getModel()).fireTableDataChanged();
			}
		} else if (e.getSource() == saveButton) {
			// TODO Validate Form
			
			getMainFrame().getController(AchievementDetailsController.class)
				.saveAchievement(packageAchievement());
		}
	}
	
	@Override
	public void valueChanged(ListSelectionEvent e) {
		// No Rows Selected
		if (!e.getValueIsAdjusting() && rulesTable.getSelectedRowCount() == 0) {
			editButton.setEnabled(false);
			deleteButton.setEnabled(false);
		} 
		// Only 1 row selected
		else if (!e.getValueIsAdjusting() && rulesTable.getSelectedRowCount() == 1) {
			editButton.setEnabled(true);
			deleteButton.setEnabled(true);
		} 
		// More then 1 row selected
		else if (!e.getValueIsAdjusting() && rulesTable.getSelectedRowCount() > 1) {
			editButton.setEnabled(false);
			deleteButton.setEnabled(true);
		}
	}
	
	private Achievement packageAchievement() {
		Achievement achievement = new Achievement();
		
		achievement.setName(nameField.getText());
		achievement.setDescription(descriptionField.getText());
		achievement.setPrize(prizeField.getText());
		
		int points = Integer.parseInt(pointsField.getText());
		achievement.setPoints(points);
		
		List<AchievementRule> tableRules = ((RulesTableModel) rulesTable.getModel()).getRules();
		Set<AchievementRule> rules = new HashSet<AchievementRule>();
		
		for (AchievementRule rule : tableRules) {
			rule.setAchievement(achievement);
			rules.add(rule);
		}
		
		achievement.setRules(rules);
		
		return achievement;
	}

	/**
	 * RulesTableModel Inner Class
	 * @author Adam Phung
	 */
	public class RulesTableModel extends AbstractTableModel {
		private static final long serialVersionUID = 1L;
		private String[] columns = { "Activity", "Source", "Condition", "Value" };
		private List<AchievementRule> rules = new ArrayList<AchievementRule>();

		public AchievementRule getRule(int index) {
			return rules.get(index);
		}
		
		public List<AchievementRule> getRules() {
			return rules;
		}
		
		public void setRules(Set<AchievementRule> ruleSet) {
			for (AchievementRule rule : ruleSet) {
				rules.add(rule);
			}
		}
		
		public void addRule(AchievementRule rule) {
			rules.add(rule);
		}
		
		public void editRule(int index, AchievementRule rule) {
			rules.remove(index);
			rules.add(rule);
		}
		
		public void deleteRule(int index) {
			rules.remove(index);
		}

		@Override
		public String getColumnName(int col) {
			return columns[col];
		}

		@Override
		public Object getValueAt(int rowIndex, int columnIndex) {
			AchievementRule rule = rules.get(rowIndex);
			switch (columnIndex) {
			case 0:
				return rule.getActivity();
			case 1:
				return rule.getMetric();
			case 2:
				return rule.getComparer();
			case 3:
				if (rule.getMetric() == Metric.Time) {
					long seconds = ((Date) rule.getValue()).getTime() / 1000;
					long hours = seconds / 3600;
					long minutes = (seconds % 3600) / 60;
					
					return String.format("%s hour(s), %s minute(s)", hours, minutes);
				}
				return rule.getValue();
			}
			return "";
		}

		@Override
		public int getRowCount() {
			return rules.size();
		}

		@Override
		public int getColumnCount() {
			return columns.length;
		}
	}
}
